package com.skt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.skt.domain.DTO.request.MerchantCostumeCreateRequest;
import com.skt.domain.DTO.request.MerchantCostumeUpdateRequest;
import com.skt.domain.ENUM.AccountStatus;
import com.skt.domain.ENUM.UserRole;
import com.skt.domain.PO.AuditLog;
import com.skt.domain.PO.Costume;
import com.skt.domain.PO.RentalOrder;
import com.skt.domain.PO.User;
import com.skt.domain.VO.MerchantBusinessStatisticsVO;
import com.skt.domain.VO.MerchantCostumeVO;
import com.skt.domain.VO.MerchantOrderVO;
import com.skt.mapper.AuditLogMapper;
import com.skt.mapper.CostumeMapper;
import com.skt.mapper.RentalOrderMapper;
import com.skt.mapper.UserMapper;
import com.skt.security.LoginUser;
import com.skt.service.MerchantService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MerchantServiceImpl extends ServiceImpl<CostumeMapper, Costume> implements MerchantService {

    private final UserMapper userMapper;
    private final CostumeMapper costumeMapper;
    private final RentalOrderMapper rentalOrderMapper;
    private final AuditLogMapper auditLogMapper;

    @Override
    public MerchantCostumeVO publishCostume(MerchantCostumeCreateRequest request) {
        // 1. 获取当前用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        Long userId = null;

        if (principal instanceof LoginUser loginUser) {
            userId = loginUser.getUserId();
        } else {
            throw new RuntimeException("用户未登录");
        }

        if (userId == null) {
            throw new RuntimeException("登录凭证失效");
        }

        // 2. 校验商家权限与状态
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        if (user.getRole() != UserRole.MERCHANT) {
            throw new RuntimeException("此用户不是商家");
        }
        if (user.getAccountStatus() != AccountStatus.ENABLED) {
            throw new RuntimeException("此用户已被禁用");
        }

        // 3. 标准化 color 字段：null 或空字符串统一转为 ""
        String color = request.getColor();
        if (color == null || color.trim().isEmpty()) {
            color = "";
        }

        // 4. 构建服装 PO 对象
        Costume costume = new Costume();
        BeanUtils.copyProperties(request, costume);
        costume.setMerchantId(userId);
        costume.setColor(color); // 使用标准化后的 color

        // 5. 执行业务规则校验：检查是否重复发布
        /*
        SELECT COUNT(*)
        FROM costume
        WHERE
          merchant_id = ?
          AND name = ?
          AND category = ?
          AND size = ?
          AND color = ?;
         */
        LambdaQueryWrapper<Costume> queryWrapper = new LambdaQueryWrapper<Costume>()
                .eq(Costume::getMerchantId, userId)
                .eq(Costume::getName, request.getName())
                .eq(Costume::getCategory, request.getCategory())
                .eq(Costume::getSize, request.getSize())
                .eq(Costume::getColor, color); // 此时 color 一定不是 null

        if (costumeMapper.selectCount(queryWrapper) > 0) {
            throw new RuntimeException("该服装（名称+类别+尺码+颜色）已存在，不可重复发布");
        }

        // 6. 持久化入库
        costumeMapper.insert(costume);

        // 7. 转换为商家专用 VO
        MerchantCostumeVO merchantCostumeVO = new MerchantCostumeVO();
        BeanUtils.copyProperties(costume, merchantCostumeVO);

        // 8. 返回结果
        return merchantCostumeVO;
    }


    /**
     * 商家更新服装信息
     * @param id
     * @param request
     * @return
     */
    @Override
    public MerchantCostumeVO updateCostume(Long id, MerchantCostumeUpdateRequest request) {
        // 1.获取当前用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("无操作权限");
        }

        Object principal = authentication.getPrincipal();
        Long userId = null;

        if (principal instanceof LoginUser loginUser) {
            userId = loginUser.getUserId();
        } else {
            throw new RuntimeException("用户未登录");
        }

        if (userId == null) {
            throw new RuntimeException("登录凭证失效");
        }
        // 2.校验商家权限与状态
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        if (user.getRole() != UserRole.MERCHANT) {
            throw new RuntimeException("用户不是商家");
        }
        if (user.getAccountStatus() != AccountStatus.ENABLED) {
            throw new RuntimeException("用户已被禁用");
        }
        // 3.校验目标服装的存在性与归属
        Costume costume = costumeMapper.selectById(id);

        if (costume == null) {
            throw new RuntimeException("服装不存在");
        }

        if (!costume.getMerchantId().equals(userId)) {
            throw new RuntimeException("此用户无权限操作该服装");
        }
        // 4.构建更新用的服装 PO 对象
        BeanUtils.copyProperties(request, costume);
        costume.setMerchantId(userId);
        costume.setUpdatedAt(LocalDateTime.now());
        // 5.执行业务规则校验
        /*
        SELECT COUNT(*)
        FROM costume
        WHERE merchant_id = 123
          AND name = '汉服'
          AND category = '古装'
          AND size = 'L'
          AND color = '红色'
          AND id != 100;  -- 👈 关键！排除自己
         */
        LambdaQueryWrapper<Costume> queryWrapper = new LambdaQueryWrapper<Costume>()
                .eq(Costume::getMerchantId, userId)
                .eq(Costume::getName, request.getName())
                .eq(Costume::getCategory, request.getCategory())
                .eq(Costume::getSize, request.getSize())
                .eq(Costume::getColor, request.getColor())
                .ne(Costume::getId, id); // ✅ 排除当前服装自身

        if (costumeMapper.selectCount(queryWrapper) > 0) {
            throw new RuntimeException("该服装（名称+类别+尺码+颜色）已存在，不可重复发布");
        }
        // 6.持久化更新
        int updated = costumeMapper.updateById(costume);
        if (updated == 0) {
            throw new RuntimeException("更新失败，请重试");
        }
        // 7.转换为商家专用 VO
        MerchantCostumeVO merchantCostumeVO = new MerchantCostumeVO();
        BeanUtils.copyProperties(costume, merchantCostumeVO); // 👈 一次性复制所有字段
        // 8.返回结果
        return merchantCostumeVO;
    }


    /**
     * 下架服装（PUT /merchant/costumes/{id}/status）
     *
     * @param id 服装ID（路径参数）
     * @return 下架后的 MerchantCostumeVO
     */
    @Override
    @Transactional
    public MerchantCostumeVO offlineCostume(Long id) {
        // 1. 获取当前用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("无操作权限");
        }

        Object principal = authentication.getPrincipal();
        Long currentUserId = null;
        if (principal instanceof LoginUser loginUser) {
            currentUserId = loginUser.getUserId();
        }
        if (currentUserId == null) {
            throw new RuntimeException("无操作权限");
        }

        // 2. 校验商家权限与状态
        User user = userMapper.selectById(currentUserId);
        if (user == null || user.getRole() != UserRole.MERCHANT || user.getAccountStatus() != AccountStatus.ENABLED) {
            throw new RuntimeException("无操作权限");
        }

        // 3. 校验目标服装的存在性与归属
        Costume costume = costumeMapper.selectById(id);
        if (costume == null) {
            throw new RuntimeException("服装不存在");
        }
        if (!currentUserId.equals(costume.getMerchantId())) {
            throw new RuntimeException("无权操作该服装");
        }

        // 4. 检查是否正在租借中（关键！防止下架正在使用的服装）
        boolean hasUnreturnedRental = rentalOrderMapper.existsUnreturnedByCostumeId(id);
        if (hasUnreturnedRental) {
            throw new RuntimeException("该服装正在租借中，无法下架");
        }

        // 5. 检查当前状态是否允许下架
        byte currentStatus = costume.getStatus();
        // 只有“在售”（1）可以下架
        if (currentStatus != 1) {
            // 如果已经是“已下架”（2），幂等处理：直接返回
            if (currentStatus == 2) {
                return fetchAndConvertVO(id);
            }
            // 其他状态（3-维修中，4-已报废）不允许下架
            throw new RuntimeException("当前服装状态不可下架");
        }

        // 6. 执行下架：状态设为 2（已下架）
        costume.setStatus((byte) 2);
        costume.setUpdatedAt(LocalDateTime.now());

        // 7. 持久化更新
        int updated = costumeMapper.updateById(costume);
        if (updated == 0) {
            throw new RuntimeException("服装更新失败，请重试");
        }

        // 8. 返回最新数据（通过辅助方法避免脏读）
        return fetchAndConvertVO(id);
    }


    /**
     * 查询商家自己的服装列表
     *
     * @param pageNum  页码（从1开始，默认1）
     * @param pageSize 每页数量（默认20，最大100）
     * @return 分页结果
     */
    @Override
    public IPage<MerchantCostumeVO> listCostumesByMerchant(Integer pageNum, Integer pageSize) {
        // 1. 获取当前用户
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth == null || !auth.isAuthenticated()) {
            throw new RuntimeException("无操作权限");
        }

        Long currentUserId = null;
        if (auth.getPrincipal() instanceof LoginUser loginUser) {
            currentUserId = loginUser.getUserId();
        }
        if (currentUserId == null) {
            throw new RuntimeException("无操作权限");
        }

        // 2. 校验商家身份
        User user = userMapper.selectById(currentUserId);
        if (user == null || user.getRole() != UserRole.MERCHANT || user.getAccountStatus() != AccountStatus.ENABLED) {
            throw new RuntimeException("无操作权限");
        }

        // 3. 校验并标准化分页参数（防止非法请求）
        pageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
        pageSize = (pageSize == null || pageSize < 1) ? 20 : Math.min(pageSize, 100);

        // 4. 构建查询条件：确保数据隔离（仅查询当前商家的服装）
        LambdaQueryWrapper<Costume> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Costume::getMerchantId, currentUserId)
                .orderByDesc(Costume::getUpdatedAt);

        // 5. 执行分页查询（数据库层强制隔离，避免越权）
        Page<Costume> page = new Page<>(pageNum, pageSize);
        Page<Costume> resultPage = costumeMapper.selectPage(page, wrapper);

        // 6. 将持久层对象（PO）转换为视图对象（VO），隐藏内部结构
        //resultPage：
        //包含从数据库查询出的分页服装数据及其分页信息（如总条数、当前页等）。
        //.convert(...)：
        //对分页结果中的每条记录进行类型转换，生成新的分页对象，保留原分页结构。
        //Lambda 转换体（含 BeanUtils.copyProperties）：
        //将每个 Costume 实体对象复制属性到 MerchantCostumeVO 视图对象，实现安全的数据封装。
        return resultPage.convert(costume -> {
            MerchantCostumeVO vo = new MerchantCostumeVO();
            BeanUtils.copyProperties(costume, vo);
            return vo;
        });
    }


    /**
     * 查看商家自己的订单列表（GET /merchant/orders）
     *
     * 要求：
     * - 仅认证且角色为商家（role = 1）、状态启用（status = 1）的用户可访问
     * - 数据隔离：只返回 merchant_id = 当前用户ID 的订单
     * - 分页参数安全处理（pageNum ≥1, pageSize ∈ [1,100]）
     * - 返回脱敏后的用户信息（手机号如 138****1234）
     * - 不泄露敏感字段，使用 MerchantOrderVO 封装
     */
    @Override
    public IPage<MerchantOrderVO> listOrdersByMerchant(Integer pageNum, Integer pageSize) {
        // 1. 获取当前认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("无操作权限");
        }

        // 2. 安全提取当前用户ID（必须是 LoginUser）
        Object principal = authentication.getPrincipal();
        Long currentUserId;
        if (principal instanceof LoginUser loginUser) {
            currentUserId = loginUser.getUserId();
        } else {
            throw new RuntimeException("无操作权限");
        }
        if (currentUserId == null) {
            throw new RuntimeException("无操作权限");
        }

        // 3. 验证用户是否为合法商家：存在、role = 1（商家）、status = 1（启用）
        User user = userMapper.selectById(currentUserId);
        if (user == null || user.getRole().getCode() != 1 || user.getAccountStatus().getCode() != 1) {
            throw new RuntimeException("无操作权限");
        }

        // 4. 标准化分页参数（确保为 effectively final）
        final int finalPageNum = (pageNum == null || pageNum <= 0) ? 1 : pageNum;
        final int finalPageSize = (pageSize == null || pageSize <= 0) ? 20 : Math.min(pageSize, 100);

        // 5. 构建查询条件：仅当前商家的订单，按创建时间倒序
        LambdaQueryWrapper<RentalOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RentalOrder::getMerchantId, currentUserId)
                .orderByDesc(RentalOrder::getCreatedAt);

        // 6. 执行分页查询（page 对象只创建一次，不被修改）
        Page<RentalOrder> page = new Page<>(finalPageNum, finalPageSize);
        Page<RentalOrder> orderPage = rentalOrderMapper.selectPage(page, wrapper);
        List<RentalOrder> orders = orderPage.getRecords();

        // 7. 若无订单，直接返回空 VO 列表
        if (orders.isEmpty()) {
            return orderPage.convert(order -> new MerchantOrderVO());
        }

        // 8. 批量查询关联的租客用户信息（构建 userMap，只赋值一次 → effectively final）
        Set<Long> userIds = orders.stream()
                .map(RentalOrder::getUserId)
                .collect(Collectors.toSet());

        // 使用三元运算确保 userMap 只初始化一次（满足 effectively final）
        final Map<Long, User> userMap = userIds.isEmpty()
                ? Collections.emptyMap()
                : userMapper.selectBatchIds(userIds).stream()
                .collect(Collectors.toMap(
                        User::getId,
                        u -> u,
                        (existing, replacement) -> existing // 防止重复 key 冲突
                ));

        // 9. 转换为安全视图对象（VO），并在 lambda 中安全使用 userMap
        return orderPage.convert(order -> {
            MerchantOrderVO vo = new MerchantOrderVO();
            BeanUtils.copyProperties(order, vo); // 复用公共字段

            // 获取租客信息并脱敏
            User customer = userMap.get(order.getUserId());
            if (customer != null) {
                // 用户名：优先真实姓名，否则用“用户_编号”
                String name = StringUtils.hasText(customer.getRealName())
                        ? customer.getRealName()
                        : "用户_" + (customer.getId() % 10000);
                vo.setCustomerName(name);

                // 手机号脱敏：138****1234
                String phone = customer.getPhone();
                if (phone != null && phone.length() >= 11) {
                    vo.setCustomerPhone(phone.substring(0, 3) + "****" + phone.substring(7));
                } else {
                    vo.setCustomerPhone("****");
                }
            } else {
                vo.setCustomerName("未知用户");
                vo.setCustomerPhone("****");
            }

            return vo;
        });
    }


    /**
     * 确认发货
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shipOrder(Long id) {
        // 1. 参数校验
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("订单ID无效");
        }

        // 2. 获取当前登录用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("无操作权限");
        }

        Object principal = authentication.getPrincipal();
        if (!(principal instanceof LoginUser loginUser) || loginUser.getUserId() == null) {
            throw new RuntimeException("无操作权限");
        }
        Long currentUserId = loginUser.getUserId();

        // 3. 验证用户是商家
        User user = userMapper.selectById(currentUserId);
        if (user == null || user.getRole().getCode() != 1) {
            throw new RuntimeException("用户状态异常，无法操作");
        }

        // 4. 查询订单
        RentalOrder order = rentalOrderMapper.selectById(id);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 5. 校验归属与状态
        if (!order.getMerchantId().equals(currentUserId)) {
            throw new RuntimeException("无权限操作该订单");
        }
        if (!order.getStatus().equals(2)) { // 2 = 已支付（待发货）
            throw new RuntimeException("仅已支付订单可发货");
        }

        // 6. 执行发货（并发安全）
        LocalDateTime now = LocalDateTime.now();
        int updated = rentalOrderMapper.updateForShip(
                id,
                currentUserId,
                2, // expected
                3, // new: 已发货
                now
        );

        if (updated == 0) {
            throw new RuntimeException("订单状态已变更，发货失败");
        }
    }


    /**
     * 确认归还完成
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmReturnCompleted(Long id) {
        // 1.校验路径参数合法性
        if (id == null || id <= 0) {
            throw new RuntimeException("订单ID错误");
        }
        // 2.验证当前用户已认证
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("用户未登录");
        }

        Object principal = authentication.getPrincipal();
        if (!(principal instanceof LoginUser loginUser) || loginUser.getUserId() == null) {
            throw new RuntimeException("无操作权限");
        }
        Long currentUserId = loginUser.getUserId();
        // 3.提取并验证商家身份
        User user = userMapper.selectById(currentUserId);

        if (user == null || user.getAccountStatus().getCode() != 1 || user.getRole().getCode() != 1) {
            throw new RuntimeException("无操作权限");
        }
        // 4.校验订单归属与状态
        RentalOrder order = rentalOrderMapper.selectById(id);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        if (!order.getMerchantId().equals(currentUserId)) {
            throw new RuntimeException("无权操作该订单");
        }

        Integer currentStatus = order.getStatus();
        // 允许确认归还的状态：2=已支付（理论上不应直接归还），3=已发货，4=已取货
        // 但根据业务，通常只有 4（已取货）才能归还；若支持退货流程，可能还有其他状态
        // 此处按合理业务假设：仅状态 4（已取货）可确认归还
        if (currentStatus != 4) {
            // 若已是 5（已归还），幂等处理
            if (currentStatus == 5) {
                return; // 幂等：已归还，直接返回
            }
            throw new RuntimeException("订单状态不可确认归还");
        }

        // 5 & 6. 在事务中执行并发安全的状态更新（使用 Integer 状态）
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        int updated = rentalOrderMapper.updateStatusByIdAndMerchantAndStatus(
                id,
                currentUserId,
                currentStatus,   // 旧状态：4
                5,               // 新状态：5 = 已归还
                now              // 归还时间
        );

        if (updated == 0) {
            // 检查是否已被其他请求处理成功
            RentalOrder latestOrder = rentalOrderMapper.selectById(id);
            if (latestOrder != null && latestOrder.getStatus() == 5) {
                return; // 幂等成功
            }
            throw new RuntimeException("订单状态已变更，无法确认归还");
        }

        // 【可选】7. 库存回补（根据订单归还的服装）
        costumeMapper.increaseStockByOrderId(id);

        // 【可选】8. 记录审计日志
        AuditLog auditLog = new AuditLog()
                .setOperatorId(currentUserId)
                .setOrderId(id)
                .setAction("CONFIRM_RETURN_COMPLETED")
                .setOperateTime(now)
                .setIpAddress("UNKNOWN")
                .setUserAgent("UNKNOWN");
        auditLogMapper.insert(auditLog);
    }


    /**
     * 查看商家经营统计（GET /merchant/costumes/statistics）
     *
     * @param startTime 起始时间（格式：yyyy-MM-dd，可选）
     * @param endTime   结束时间（格式：yyyy-MM-dd，可选）
     * @return 商家经营统计 VO
     */
    @Override
    public MerchantBusinessStatisticsVO getBusinessStatistics(String startTime, String endTime) {
        // 常量定义（避免魔法数字）
        final int MERCHANT_ROLE = 1;
        final int USER_ACTIVE_STATUS = 1;
        final int ORDER_STATUS_RETURNED = 5;

        // 1. 获取并校验当前认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new RuntimeException("用户未登录");
        }

        Object principal = authentication.getPrincipal();
        Long currentUserId;
        if (principal instanceof LoginUser loginUser) {
            currentUserId = loginUser.getUserId();
        } else {
            throw new RuntimeException("无效用户凭证");
        }
        if (currentUserId == null) {
            throw new RuntimeException("用户ID缺失");
        }

        // 2. 验证商家身份与账户状态
        User user = userMapper.selectById(currentUserId);
        if (user == null || user.getRole() != UserRole.MERCHANT || user.getAccountStatus() != AccountStatus.ENABLED) {
            throw new RuntimeException("仅活跃商家可查看经营统计");
        }

        // 3. 解析并校验时间范围参数（可选）
        LocalDateTime startDateTime;
        LocalDateTime endDateTime;

        if (StringUtils.hasText(startTime) || StringUtils.hasText(endTime)) {
            if (!StringUtils.hasText(startTime) || !StringUtils.hasText(endTime)) {
                throw new RuntimeException("参数错误：startTime 和 endTime 必须同时提供");
            }

            java.time.LocalDate startLocalDate;
            java.time.LocalDate endLocalDate;
            try {
                startLocalDate = java.time.LocalDate.parse(startTime);
                endLocalDate = java.time.LocalDate.parse(endTime);
            } catch (Exception e) {
                throw new RuntimeException("参数错误：时间格式无效，应为 yyyy-MM-dd");
            }

            // 校验 startTime <= endTime
            if (startLocalDate.isAfter(endLocalDate)) {
                throw new RuntimeException("参数错误：startTime 不能晚于 endTime");
            }

            // 校验 endTime 不得晚于当前日期（按天比较）
            java.time.LocalDate today = java.time.LocalDate.now();
            if (endLocalDate.isAfter(today)) {
                throw new RuntimeException("参数错误：endTime 不能晚于当前日期");
            }

            // 校验时间跨度不超过 365 天（包含首尾）
            long spanDays = java.time.temporal.ChronoUnit.DAYS.between(startLocalDate, endLocalDate) + 1;
            if (spanDays > 365) {
                throw new RuntimeException("参数错误：时间跨度不得超过 365 天");
            }

            // 安全的时间范围：[start 00:00:00, end+1 00:00:00)
            startDateTime = startLocalDate.atStartOfDay();
            endDateTime = endLocalDate.plusDays(1).atStartOfDay();
        } else {
            // 默认最近30天（包含今天）
            java.time.LocalDate today = java.time.LocalDate.now();
            java.time.LocalDate thirtyDaysAgo = today.minusDays(29); // 29天前 + 今天 = 30天
            startDateTime = thirtyDaysAgo.atStartOfDay();
            endDateTime = today.plusDays(1).atStartOfDay();
        }

        // 4. 执行多维度经营数据聚合查询（所有查询限定 merchantId = currentUserId）

        // 总订单数
        long totalOrders = rentalOrderMapper.selectCount(
                new LambdaQueryWrapper<RentalOrder>()
                        .eq(RentalOrder::getMerchantId, currentUserId)
                        .ge(RentalOrder::getCreatedAt, startDateTime)
                        .lt(RentalOrder::getCreatedAt, endDateTime)
        );

        // 已完成订单数（状态为 5：已归还）
        long completedOrders = rentalOrderMapper.selectCount(
                new LambdaQueryWrapper<RentalOrder>()
                        .eq(RentalOrder::getMerchantId, currentUserId)
                        .ge(RentalOrder::getCreatedAt, startDateTime)
                        .lt(RentalOrder::getCreatedAt, endDateTime)
                        .eq(RentalOrder::getStatus, ORDER_STATUS_RETURNED)
        );

        // 总收入金额（使用 BigDecimal，避免精度丢失）
        BigDecimal totalIncome = rentalOrderMapper.selectTotalIncomeByMerchantAndTime(
                currentUserId, startDateTime, endDateTime
        );
        if (totalIncome == null) {
            totalIncome = BigDecimal.ZERO;
        }

        // 当前在租服装数量（状态为 3=已发货 或 4=已取货，且未归还）
        long rentingCount = rentalOrderMapper.selectRentingCountByMerchant(
                currentUserId, startDateTime, endDateTime
        );

        // 热门服装 TOP5
        List<MerchantBusinessStatisticsVO.HotCostume> hotCostumes = new ArrayList<>();
        List<Map<String, Object>> hotCostumeList = rentalOrderMapper.selectHotCostumesByMerchant(
                currentUserId, startDateTime, endDateTime
        );
        if (hotCostumeList != null && !hotCostumeList.isEmpty()) {
            hotCostumes = hotCostumeList.stream().map(map -> {
                MerchantBusinessStatisticsVO.HotCostume hot = new MerchantBusinessStatisticsVO.HotCostume();
                hot.setCostumeId((Long) map.get("costumeId"));
                hot.setCostumeName((String) map.get("costumeName"));
                hot.setRentalCount(((Number) map.get("rentalCount")).intValue());
                return hot;
            }).collect(Collectors.toList());
        }

        // 日均订单量与日均收入
        long actualDays = java.time.temporal.ChronoUnit.DAYS.between(
                startDateTime.toLocalDate(),
                endDateTime.toLocalDate()
        ); // 注意：因为 endDateTime 是 end+1 的 00:00，所以 actualDays 就是实际天数
        double avgDailyOrders = actualDays > 0 ? (double) totalOrders / actualDays : 0.0;
        BigDecimal avgDailyIncome = actualDays > 0
                ? totalIncome.divide(BigDecimal.valueOf(actualDays), 2, RoundingMode.HALF_UP)
                : BigDecimal.ZERO;

        // 5. 构建返回 VO
        MerchantBusinessStatisticsVO vo = new MerchantBusinessStatisticsVO();
        vo.setTotalOrders(totalOrders);
        vo.setCompletedOrders(completedOrders);
        vo.setTotalIncome(totalIncome);
        vo.setRentingCostumeCount(rentingCount);
        vo.setHotCostumes(hotCostumes);
        vo.setAvgDailyOrders(BigDecimal.valueOf(avgDailyOrders).setScale(2, RoundingMode.HALF_UP));
        vo.setAvgDailyIncome(avgDailyIncome);
        vo.setStartTime(startDateTime.toLocalDate().toString());
        vo.setEndTime(endDateTime.minusDays(1).toLocalDate().toString()); // 还原为用户输入的结束日

        return vo;
    }

    /**
     * 重新从数据库查询并转换为 VO（避免返回未刷新的缓存或旧对象）
     */
    private MerchantCostumeVO fetchAndConvertVO(Long costumeId) {
        Costume freshCostume = costumeMapper.selectById(costumeId);
        if (freshCostume == null) {
            throw new RuntimeException("服装数据异常");
        }
        MerchantCostumeVO vo = new MerchantCostumeVO();
        BeanUtils.copyProperties(freshCostume, vo);
        return vo;
    }
}